package cn.amossun.starter.mybatis.data.security.util;

import cn.hutool.core.codec.Base64Decoder;
import cn.hutool.core.codec.Base64Encoder;
import lombok.Data;
import lombok.extern.slf4j.Slf4j;

import javax.crypto.Cipher;
import javax.crypto.SecretKey;
import javax.crypto.spec.IvParameterSpec;
import javax.crypto.spec.SecretKeySpec;
import java.nio.charset.Charset;

/**
 * @description:
 * @author: Amos.Sun
 * @DateTime: 2020-03-07 15:11
 **/
@Data
@Slf4j
public class AesUtil {

    private String sKey = "emfVqh6FaDJpO7NCECSVIWoWwurMxJWq";// key必须为16/24/32位

    private String offset = "XzGczwYoCoG72Xfj";// 密钥默认偏移

    private String cipherModePadding = "AES/CBC/PKCS7Padding";// AES/CBC/PKCS7Padding

    private String characterName = "UTF-8";

    private byte[] iv = offset.getBytes();

    private final SecretKeySpec secretKeySpec;

    private final IvParameterSpec ivParameterSpec;
    
    private static AesUtil instance = null;

    public AesUtil newInstance(String sKey, String offset, String cipherModePadding) {
        this.sKey = sKey;
        this.offset = offset;
        this.cipherModePadding = cipherModePadding;
        if (instance == null) {
            synchronized (AesUtil.class) {
                if (instance == null) {
                    instance = new AesUtil();
                }
            }
        }
        return instance;
    }

    public static AesUtil getInstance() {
        if (instance == null) {
            synchronized (AesUtil.class) {
                if (instance == null) {
                    instance = new AesUtil();
                }
            }
        }
        return instance;
    }

    private AesUtil() {
        byte[] skAsByteArray = sKey.getBytes(Charset.forName(getCharacterName()));
        secretKeySpec = new SecretKeySpec(skAsByteArray, "AES");
        ivParameterSpec = new IvParameterSpec(iv);
    }

    /*public static void main(String[] args) {
        AesUtil aesUtil = AesUtil.getInstance();

        String encryptStr = aesUtil.encrypt("amossun-amossun-amossun".getBytes(StandardCharsets.UTF_8));
        System.out.println("encryptStr: " + encryptStr);

        String decryptStr = aesUtil.decrypt(encryptStr);
        System.out.println("decryptStr: " + decryptStr);
    }*/

    public String encrypt(byte[] plaintext) {
        try {
            byte[] ciphertext = encrypt(cipherModePadding, secretKeySpec, ivParameterSpec, plaintext);
            String base64_ciphertext = Base64Encoder.encode(ciphertext);
            return base64_ciphertext;
        } catch (Exception exception) {
            log.error(exception.getMessage());
            return null;
        }
    }

    public String decrypt(String ciphertext) {
        try {
            byte[] s = Base64Decoder.decode(ciphertext.getBytes(getCharacterName()));
            String decrypted = new String(decrypt(cipherModePadding, secretKeySpec, ivParameterSpec, s));
            return decrypted;
        } catch (Exception exception) {
            log.error(exception.getMessage());
            return null;
        }
    }

    public byte[] encrypt(String cipherModePadding, SecretKey secretKey, IvParameterSpec ivParameterSpec, byte[] msg) {
        try {
            Cipher c = Cipher.getInstance(cipherModePadding);
            c.init(Cipher.ENCRYPT_MODE, secretKey, ivParameterSpec);
            return c.doFinal(msg);
        } catch (Exception exception) {
            log.error(exception.getMessage());
        }
        return null;
    }

    public byte[] decrypt(String cipherModePadding, SecretKey secretKey, IvParameterSpec ivParameterSpec, byte[] ciphertext) {
        try {
            Cipher c = Cipher.getInstance(cipherModePadding);
            c.init(Cipher.DECRYPT_MODE, secretKey, ivParameterSpec);
            return c.doFinal(ciphertext);
        } catch (Exception exception) {
            log.error(exception.getMessage());
        }
        return null;
    }

}
